class Recibo < ActiveRecord::Base
  validates_presence_of :valor_bruto,:valor_neto,:mes,:anho,:usuario_id
  #validates_uniqueness_of :mes, :scope => [:anho,:usuario_id,:aguinaldo]

  belongs_to :usuario
  belongs_to :sucursal
  has_many :movimientos
  before_destroy :actualizar_movimientos
  named_scope :por_mes_y_anio, lambda{|mes,anio| {:conditions => ["mes=? AND anho =?",mes,anio] }}
  named_scope :por_periodo, lambda{|i,f| {:conditions => ["(anho BETWEEN ? and ?) and (mes BETWEEN ? and ?)",i.year,f.year,i.month,f.month] }}
  named_scope :de_usuarios_activos, :include=>:usuario,:conditions=>["usuarios.activo=1"]
  named_scope :por_anho, lambda{|anio| {:conditions=>["anho=?",anio]}}
  named_scope :anterior_al_mes, lambda{|mes| {:conditions=>["mes<?",mes]}}
  named_scope :por_usuario_id, lambda{|id| {:include=>:usuario,:conditions=>["usuarios.id=#{id}"]}}
  named_scope :aguinaldos?, lambda{|aguinaldo| {:conditions=>["aguinaldo=?",aguinaldo]}}

  delegate :empresa_id,:to => :sucural  
  delegate :nombre,:to => :sucural,:prefix=>true
  delegate :empresa_nombre,:to => :sucural  
  
  attr_accessor :acreditaciones
  Tipos=[["Salarios",0],["Aguinaldos",1],["Ambos",'']]
  #En algunos títulos con más de una palabra se utilizan dos espacios para
  #separar las palabras, esto sirve en la vista para poder reemplazarlos por "<br/>"
  Recibo::HEADERS_FOR_RES_MOV=["Filial","Sueldo","Descuentos","Quincena","PRAEP","IVA","Comision",
    "Horas  Extra","Viaticos","Bonificacion","Regencia","Acreditaciones",
    "Plus Gerente/Supervisor","Premio Visitadores","Sueldo  Depositado  en banco","Liberado  por  caja"]
  def sucursal_nombre_completo
    empresa_nombre+" - "+sucursal.nombre
  end    
  def empresa_nombre
    sucursal.empresa_nombre
  end    
  
  def periodo
    self.mes.to_s+'/'+self.anho.to_s
  end
  
  def actualizar_movimientos
    Movimiento.update_all("recibo_id=null","recibo_id = #{self.id}")
  end

  def self.generar_aguinaldo(user,args)
    aguinaldo_mismo_anio=Recibo.anterior_al_mes(args[:mes]).find_by_anho_and_aguinaldo(args[:anho],true)

    from = aguinaldo_mismo_anio ? Time.mktime(aguinaldo_mismo_anio.anho,aguinaldo_mismo_anio.mes).advance(:months=>1) : Time.mktime(args[:anho])
    to = Time.mktime(args[:anho], args[:mes]).at_end_of_month
    args[:total]=self.get_totales_aguinaldo(user,from,to)[13][0]
    recibo=crear_recibo(user,args,true)
    return nil unless recibo
    recibo.valor_neto+=recibo.valor_bruto*0.1 if recibo.usuario.iva_aguinaldo
    recibo.valor_neto-=Movimiento.adelantos_de_aguinaldo.periodo(from,to).find_all_by_usuario_id(user.id).sum(&:valor)
    recibo.save
    recibo
  end

  def self.get_totales_aguinaldo(user,from,to,dividir=true)
    t = dividir ? {13=>[0,'']} : {1=>[0,''],2=>[0,''],3=>[0,''],4=>[0,''],5=>[0,''],6=>[0,''],7=>[0,''],8=>[0,''],9=>[0,''],10=>[0,''],11=>[0,''],12=>[0,''],13=>[0,'']}
    user.recibos.por_periodo(from,to).aguinaldos?(false).each_with_index do |r,i|
      t[r.mes]=[0,'']
      t[r.mes][0],t[r.mes][1]=get_aguinaldo_mes(r,i)
      t[13][0]+=t[r.mes][0]
    end    
    dividir ? t[13][0]/=12 : t[13][0]=0
    t[13][0]=sprintf("%.0f",t[13][0]).to_f
    t
  end

  def self.generar(user, args)
    #Definir periodo del mes si no se puso algo
    mes = args[:mes]
    anho = args[:anho]
    from = args[:desde] ? DateTime.strptime(args[:desde], "%d/%m/%Y") : Time.mktime(anho, mes)
    to = args[:hasta] ? DateTime.strptime(args[:hasta], "%d/%m/%Y") :  Time.mktime(anho, mes).at_end_of_month
    args[:total]=user.sueldo
    recibo = crear_recibo(user,args,false)
    return nil if recibo.nil?
    
    descuentos = 0
    adicionales = 0

    #generar movimientos varaibles desde predefinidos
    unless args[:preview]
      user.generar_predefinidos(anho, mes) unless Movimiento.check_predefinidos(anho, mes)
    end

    #recorrer movimientos variables
    #TODO: ver recibo_id deberia buscar solo nils
    #TODO: PARCHE eliminar named_scope ignorar_liberado_por_caja
    user.movimientos.sin_adelantos_de_aguinaldo.ignorar_liberado_por_caja.periodo(from, to).each do |mov|
      descuentos += mov.valor unless mov.sumar?
      adicionales += mov.valor if mov.sumar?
      mov.update_attribute(:recibo_id, recibo.id) unless args[:preview]
    end


    recibo.valor_neto ||= 0
    recibo.valor_neto -= descuentos
    recibo.valor_neto += adicionales
    recibo.save unless args[:preview]
    recibo
  end

  def tipo
    self.aguinaldo ? "Aguinaldo" : "Salario"
  end

  def partial
    self.aguinaldo ? "detalles_aguinaldo" : "detalles_salario"
  end

  def acreditaciones
    @acreditacion||=get_acreditaciones
  end

  #TODO: AGREGAR DOCUMENTACION!
  def get_acreditaciones
    case self.aguinaldo?
    when true
      adelantos=0
      creditos=0
      aguinaldo_mismo_anio=Recibo.anterior_al_mes(self.mes).find_by_anho_and_aguinaldo(self.anho,true)
      from = aguinaldo_mismo_anio ? Time.mktime(aguinaldo_mismo_anio.anho,aguinaldo_mismo_anio.mes).advance(:months=>1) : Time.mktime(self.anho)
      to=Time.mktime(self.anho,self.mes).at_end_of_month
      creditos=Recibo.get_totales_aguinaldo(self.usuario, from, to,false)
      creditos[13][0]=self.valor_bruto
      adelantos=Movimiento.adelantos_de_aguinaldo.periodo(from,to).find_all_by_usuario_id(self.usuario_id).sum(&:valor)
      {:creditos=>creditos,:adelantos =>adelantos}
    else
      self.movimientos.creditos
    end
  end

  def ref
    "Recibo #{self.mes}-#{self.anho}"
  end

  def valor
    self.valor_neto
  end

  def descuentos
    cred = 0
    self.movimientos.descuentos.each{|mov| cred += mov.valor unless mov.tipo_movimiento.try(:nombre) =~ /^Quincena+/i }
    cred
  end

  def sueldo_bruto_beneficios
    cred = self.valor_bruto
    self.movimientos.creditos.each{|mov| cred += mov.valor} 
    cred ? cred : 0
  end

  def quincena
    cred = 0
    self.movimientos.descuentos.each{|mov| cred += mov.valor if mov.tipo_movimiento.nombre =~ /^Quincena+/i }
    cred
  end

  def ausencias
    cred = 0
    self.movimientos.descuentos.each{|mov| cred += mov.valor if mov.tipo_movimiento.nombre =~ /^Ausencia+/i }
    cred
  end

  def total(nombre)
    self.movimientos.send(nombre).sum(:valor)
  end

  def total_acreditacion
    acreditacion=0
    self.movimientos.creditos.each { |mov| acreditacion+= mov.valor if mov.tipo_movimiento.nombre =~/^Acreditacion+/i }
    acreditacion
  end

  def total_viaticos
    viaticos=0
    self.movimientos.each { |mov| viaticos+= mov.valor if (mov.tipo_movimiento.nombre =~/^Viatico+/i)  }
    viaticos
  end

  def self.generar_resumen_movimientos(tipo,condiciones,as_file=false)
    recibos = self.find(:all, :conditions => condiciones, :joins => :usuario )
    fields={
      :lugar => '',
      :sueldo_bruto => 0,
      :quincena => 0,
      :descuentos => 0,
      :acreditaciones => 0,
      :liberado_caja => 0,

      :depositado_en_banco=>0,
      :praeps => 0,
      :ivas => 0,
      :comisiones => 0,
      :horas_extras => 0,
      :viaticos => 0,
      :bonificaciones => 0,
      :regencias => 0,
      :plus => 0,
      :premios => 0
    }
    datos={}
		recibos= tipo == "e" ? recibos.group_by(&:empresa_nombre) : recibos.group_by(&:sucursal_nombre_completo)
    lugares=recibos.keys
    
    lugares.each  do |lugar|
      datos[lugar]||= fields.clone
      recibos[lugar].each do |recibo|
        next if recibo.valor_neto.to_i<=0
        if (recibo.num_cuenta.blank? or recibo.num_cuenta.to_i==0 )
          datos[lugar][:liberado_caja] += recibo.valor_neto
        else        
          datos[lugar][:depositado_en_banco] += recibo.valor_neto
          datos[lugar][:viaticos] += recibo.total_viaticos
          datos[lugar][:quincena] += recibo.quincena
          datos[lugar][:descuentos] += recibo.descuentos
          datos[lugar][:sueldo_bruto] += recibo.sueldo_bruto_beneficios
          datos[lugar][:acreditaciones] += recibo.total_acreditacion
          [:praeps,:ivas,:comisiones,:horas_extras,:bonificaciones,:regencias,:plus,:premios].each do |dato|
            datos[lugar][dato] += recibo.total(dato)
          end          
        end        
      end
      no_considerado_sueldo=0
      [:praeps,:ivas,:comisiones,:horas_extras,:bonificaciones,:regencias,:plus,:premios,:acreditaciones,:viaticos].each do |movimiento|
        no_considerado_sueldo+=datos[lugar][movimiento]
      end      
      datos[lugar][:depositado_en_banco]-=no_considerado_sueldo      
    end
    
		totales={}
		totales['~Totales~']=fields.clone
    datos.keys.each do |filial|
      datos[filial].keys.each do |dato|
        totales['~Totales~'][dato]+=datos[filial][dato]
      end
    end
		datos.merge!(totales)    
    
    as_file ? generar_archivo_resumen_movimientos(datos) : datos
  end

  def self.generar_archivo_resumen_movimientos(datos)
    FasterCSV.generate(:encoding=>'U') do |csv|
      csv << Recibo::HEADERS_FOR_RES_MOV
      datos.keys.sort.each do |filial|
        row=[]
        row<<filial
        [:sueldo_bruto,:descuentos,:quincena,:praeps,:ivas,:comisiones,:horas_extras,:viaticos,:bonificaciones,:regencias,:acreditaciones,:plus,:premios].each do |key|
          row<<datos[lugar][key]
        end
        row<<datos[lugar][:depositado_en_banco]
        row<<datos[lugar][:liberado_caja]
        csv << row
      end
    end
  end
  
  private
  #TODO REMOVE PATCH ADAMS HERE =D
  def self.get_aguinaldo_mes(r,index)
    ingreso=r.usuario.antiguedad["fecha_ingreso"]
    descripcion=[]
    descripcion<<"Salario"
    valor_bruto=r.valor_bruto.to_f
    #    logger.info "\n\n=============================================================="
    #    logger.info "antigu => #{ingreso.inspect}"
    #    logger.info "ingreso => #{ingreso.inspect}"
    #    logger.info "index => #{index}"
    #    logger.info "==============================================================\n\n"
    if (!ingreso.nil? and ingreso.year==r.anho and ingreso.month==r.mes) or (index==0 and !ingreso.nil? and ingreso.year==r.anho and ingreso.month==r.mes)
      total = (sprintf("%.0f",valor_bruto/30).to_f)*(30-ingreso.day)
    else
      total = valor_bruto
    end
    logger.info "\n\n\ntotal=>#{total}"
    logger.info "\n\n\nrecibo=>#{r.inspect}"
    scope = r.usuario.comision_aguinaldo ?  "all" : "sin_comisiones" #PATCH
    r.movimientos.por_afecta_aguinaldo(true).send(scope).each do |m|
      total+= m.sumar? ? m.valor : -m.valor
      descripcion<<m.descripcion
    end
    #TODO: PARCHE eliminar esta seccion
    periodo=Date.new(r.anho,r.mes)
    r.usuario.movimientos.solo_liberados_por_caja.periodo(periodo.beginning_of_month,periodo.end_of_month).each do |m|
      total+= m.sumar? ? m.valor : -m.valor
      descripcion<<m.descripcion
    end
    #============================================================
    [total.to_f, descripcion.join(", ")]
  end

  def self.crear_recibo(user,args,aguinaldo)
    return nil if args[:total].nil?
    recibo = user.recibos.new(:mes=>args[:mes],:anho=>args[:anho],:aguinaldo=>aguinaldo,:sucursal_id=>user.sucursal_id,:num_cuenta=>user.num_cuenta)
    recibo.valor_bruto = recibo.valor_neto = args[:total]
    recibo.save unless args[:preview]
    recibo
  end
end
